<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>对象/数组响应化</title>
</head>
<body>
  <script>
    let data = {
      name: 'Alan',
      age: 32,
      obj: {
        text: '很好'
      },
      course: [
        {
          name: '语文'
        },
        {
          name: '数学'
        },
        {
          name: '英语'
        }
      ]
    }
    // 数组响应式
    function ArrayFunction () {
      const ARRAY_METHOD = ['push','pop','shift','unshift','reverse','sort','splice']
      const array_method = Object.create(Array.prototype)
      ARRAY_METHOD.forEach(method => {
        array_method[method] = function () {
          // 将数据进行响应式化
          Array.from(arguments).forEach(item => {
            reactify(item)
          })
          // 把当前方法绑定到Array.prototype的原型上
          const res = Array.prototype[method].apply(this, arguments)
          return res
        }
      })
      return array_method
    }
    // 使数据响应化
    function defineReactive (target, key, value, enumerable) {
      Object.defineProperty(target, key, {
        enumerable: !!enumerable,
        configurable: true,
        get () {
          return value
        },
        set (newValue) {
          value = newValue
        }
      })
    }
    // 对象响应化
    function reactify (data) {
      Object.keys(data).forEach(key => {
        let value = data[key]
        if (Array.isArray(value)) {
          value.__proto__ = ArrayFunction()
          value.forEach(item => {
            reactify(item) // 递归
          })
        } else if (typeof value === 'object' && value !== null && !Array.isArray( value )) {
          reactify(value)
        } else {
          defineReactive(data, key, value, true)
        }
      })
    }
    reactify(data)
  </script>
</body>
</html>